import { Block, Line, Group, MyRect, MyMark, MyTriangle, MyLine, MyText, MyControlPoint, Link, MyPolygon, MyCircle, MyArrow, MyCustom, } from "./Index"
import IPoint from "./interface/IPoint";
import { getMousePos, isPointInRect, runAnimate, isPosInRotationRect, getRotatePoint, getMinDistLine, getVectorLength, point2SegDist, getVector } from "./utils";
import { CoordinateSystem, ControlPoint, BlockType, MyEvent, LinkMark, FontFamily } from "./Constants";
import ScaleRuler from "./ScaleRule";
import Shortcuts from "./Shortcuts";
import Stack from "./Stack";
import IStatus from "./interface/IStatus";
import IConfig from "./interface/IConfig";
import Node from "./features/Node";
import { fontMap } from "./Maps"

class GridSystem {

    static groups: Group[] = []  // 多个组
    static links: Link[] = []  // 多个连线
    static isSelectArea = false;  // 是否进入绘制选取区域模式
    static blocksInArea: Block[] = [];  // 被区域寻中的元素

    static cbTransform = false; // 元素是否可被形变
    static cbAdsorption = false; // 是否开启吸附
    static cbSelect = true;  // 元素是否可被选择
    static cbMove = true;  // 元素是否可被拖拽
    static cbOverlap = true;  // 元素间是否可重叠
    static cbTouch = false;  // 是否封装检测

    static onlyRatioTransform = false; // 是否按比例缩放
    static onlyVerticalTransform = false; // 是否只垂直缩放
    static onlyHorizonTransform = false; // 是否只水平缩放
    static onlyVerticalMove = false; // 是否只垂直移动
    static onlyHorizonMove = false; // 是否只水平移动

    static gls: GridSystem;

    myCanvas: HTMLCanvasElement;
    ctx: CanvasRenderingContext2D;
    canvasWidth: number;
    canvasHeight: number;

    pageSlicePos: IPoint = { x: 120, y: 120 }; // 相对坐标， 值是像素坐标
    scale: number = CoordinateSystem.NATIVE_SCALE; // 缩放比例

    blocks: Block[] = []; // 物体集合
    lines: Line[] = []; // 线段集合
    links: Link[] = [];   // 关系线集合

    scaleRuler: ScaleRuler  // 比例尺
    stack: Stack;   // 撤销恢复的对象

    lastGirdSize: number;  // 上一次的grid大小
    lastPageSlicePos: IPoint;  // 上一次的中心点坐标
    lastDrawTime: number;   // 记录绘制函数调用时间,防止多次触发
    lastMouseDownTime: number;   // 记录上一次点击事件,判断是否双击
    timer: number;

    rectArea: Block | null;  // 自定义绘制区域,框选

    focusNode: Node | Line | null | undefined;  // 获取焦点的元素
    hoverNode: Block | Line | null | undefined;  // 是否开启悬浮样式小手
    dragNode: Block | Line | null | undefined;   // 正在被拖拽的元素
    mouseMovePoint: IPoint | null;

    testPoint: Block | null;  // 测试用，看点在哪

    constructor(canvasDom: HTMLCanvasElement) {
        this.myCanvas = canvasDom;
        if (!this.myCanvas) {
            this.myCanvas = document.createElement("canvas");
            throw "画布元素不存在!"
        }
        this.ctx = this.myCanvas.getContext("2d") || new CanvasRenderingContext2D();
        if (!this.ctx) throw "上下文获取失败!"
        // 获取Canvas的width、height
        this.canvasWidth = this.ctx.canvas.width;
        this.canvasHeight = this.ctx.canvas.height;

        this.initEventListener();

        this.scaleRuler = new ScaleRuler(this)
        this.stack = new Stack();

        this.rectArea = null;

        this.lastGirdSize = 0;
        this.lastPageSlicePos = { x: this.pageSlicePos.x, y: this.pageSlicePos.y }
        this.lastDrawTime = 0;
        this.lastMouseDownTime = 0;
        this.timer = 0;

        this.dragNode = null;
        this.focusNode = null;
        this.hoverNode = null;
        this.mouseMovePoint = null;

        this.testPoint = new MyRect(10, 10, .6, .6);
        this.testPoint.fill = "#000";

        GridSystem.gls = this;
        this.loadFont(FontFamily.ZONGYI);  // 加载字体
        // 一开始就不断地渲染,性能更好
        let that = this;
        (function loopDraw() {
            that.drawLineGrid();
            window.requestAnimationFrame(loopDraw);
        })()
        // this.initData();  // 初始化数据
        // this.blocks.push(this.testPoint)
        // this.dragNode = [];
    }

    // 初始化数据,渲染已存储的数据
    initData() {
        let stageInfo = localStorage.getItem("stageInfo")
        // if (stageInfo) {
        //     stageInfo = JSON.parse(stageInfo);
        //     if (stageInfo && Array.isArray(stageInfo) && stageInfo.length > 0) {
        //         stageInfo.forEach(item => {
        //             let block: Block | null = null;
        //             block = GridSystem.createFetureByClass(item)
        //             block && this.blocks.push(block)
        //         })
        //     }
        // }
    }

    /**
     * 绘制网格,以及网格内的一切元素
     * @param mousemovePoint 
     */
    drawLineGrid = (mousemovePoint?: IPoint, mousedownPoint?: IPoint) => {
        // if (new Date().getTime() - this.lastDrawTime < CoordinateSystem.DRAW_INTERVAL) {
        //     this.timer && clearTimeout(this.timer)
        //     return
        // } else {
        // }  // 防止触发太快
        this.lastDrawTime = new Date().getTime();

        this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
        this.ctx.save();

        /*获取元素*/
        /*获取绘图工具*/
        // 设置网格大小
        var girdSize = this.getPixelSize(CoordinateSystem.GRID_SIZE);
        this.lastGirdSize = girdSize;  // 记录上一次的gridSize

        // 在 pageSlicePos 的 x，y 点位画一个 10 * 10 的红色标记用来表示当前页面的 0 0 坐标
        this.ctx.lineWidth = 1;
        this.ctx.strokeStyle = "#002766";
        this.ctx.fillRect(
            this.pageSlicePos.x - CoordinateSystem.GRID_SIZE,
            this.pageSlicePos.y - CoordinateSystem.GRID_SIZE,
            10,
            10
        ); // 效果图红色小方块

        const canvasXHeight = this.canvasHeight - this.pageSlicePos.y;
        const canvasYWidth = this.canvasWidth - this.pageSlicePos.x;
        // 从 this.pageSlicePos.y 处开始往 Y 轴正方向画 X 轴网格  向上画横线
        const xPageSliceTotal = Math.ceil(canvasXHeight / girdSize);
        for (let i = 0; i < xPageSliceTotal; i++) {
            this.ctx.beginPath(); // 开启路径，设置不同的样式
            this.ctx.moveTo(0, this.pageSlicePos.y + girdSize * i);
            this.ctx.lineTo(this.canvasWidth, this.pageSlicePos.y + girdSize * i);
            this.ctx.strokeStyle =
                i === 0
                    ? CoordinateSystem.ZERO_COLOR
                    : i % CoordinateSystem.GRID_SIZE === 0
                        ? CoordinateSystem.SOLID_COLOR
                        : CoordinateSystem.DASHED_COLOR; // 如果为 0 则用蓝色标记，取余 5 为实线，其余为比较淡的线
            this.ctx.stroke();
        }

        // 从 this.pageSlicePos.y 处开始往 Y 轴负方向画 X 轴网格  向下画横线
        const xRemaining = this.pageSlicePos.y;
        const xRemainingTotal = Math.ceil(xRemaining / girdSize);
        for (let i = 0; i < xRemainingTotal; i++) {
            if (i === 0) continue;
            this.ctx.beginPath(); // 开启路径，设置不同的样式
            this.ctx.moveTo(0, this.pageSlicePos.y - girdSize * i); // -0.5是为了解决像素模糊问题
            this.ctx.lineTo(this.canvasWidth, this.pageSlicePos.y - girdSize * i);
            this.ctx.strokeStyle =
                i === 0
                    ? CoordinateSystem.ZERO_COLOR
                    : i % CoordinateSystem.GRID_SIZE === 0
                        ? CoordinateSystem.SOLID_COLOR
                        : CoordinateSystem.DASHED_COLOR; // 如果为 0 则用蓝色标记，取余 5 为实线，其余为比较淡的线
            this.ctx.stroke();
        }

        // 从 this.pageSlicePos.x 处开始往 X 轴正方向画 Y 轴网格
        const yPageSliceTotal = Math.ceil(canvasYWidth / girdSize); // 计算需要绘画y轴的条数
        for (let j = 0; j < yPageSliceTotal; j++) {
            this.ctx.beginPath(); // 开启路径，设置不同的样式
            this.ctx.moveTo(this.pageSlicePos.x + girdSize * j, 0);
            this.ctx.lineTo(this.pageSlicePos.x + girdSize * j, this.canvasHeight);
            this.ctx.strokeStyle =
                j === 0
                    ? CoordinateSystem.ZERO_COLOR
                    : j % CoordinateSystem.GRID_SIZE === 0
                        ? CoordinateSystem.SOLID_COLOR
                        : CoordinateSystem.DASHED_COLOR; // 如果为 0 则用蓝色标记，取余 5 为实线，其余为比较淡的线
            this.ctx.stroke();
        }

        // 从 this.pageSlicePos.x 处开始往 X 轴负方向画 Y 轴网格
        const yRemaining = this.pageSlicePos.x;
        const yRemainingTotal = Math.ceil(yRemaining / girdSize);
        for (let j = 0; j < yRemainingTotal; j++) {
            if (j === 0) continue;
            this.ctx.beginPath(); // 开启路径，设置不同的样式
            this.ctx.moveTo(this.pageSlicePos.x - girdSize * j, 0);
            this.ctx.lineTo(this.pageSlicePos.x - girdSize * j, this.canvasHeight);
            this.ctx.strokeStyle =
                j === 0
                    ? CoordinateSystem.ZERO_COLOR
                    : j % CoordinateSystem.GRID_SIZE === 0
                        ? CoordinateSystem.SOLID_COLOR
                        : CoordinateSystem.DASHED_COLOR; // 如果为 0 则用蓝色标记，取余 5 为实线，其余为比较淡的线
            this.ctx.stroke();
        }
        this.ctx.restore();
        this.drawBlocks(mousemovePoint, mousedownPoint);
        this.drawLinks();
        this.drawLines(mousemovePoint, mousedownPoint);
        this.scaleRuler && this.scaleRuler.draw(this);
    };

    /**
     * 以绝对坐标绘制网格内的所有元素, 绘制点状元素
     * @param mouseMoveDist 
     */
    drawBlocks(mousemovePoint?: IPoint, mousedownPoint?: IPoint) {
        // 绘制画布上的所有的元素
        this.blocks.forEach((block) => {
            if (this.cbDrawClass(block) && !block.parentBlock) {
                var { x: x1, y: y1, width: width1, height: height1 } = this.getPixelPosAndWH(block);
                // if (!this.isBoundrayPointInScreen(block, x1, y1, width1, height1, block.angle)) return;  // 屏幕外的元素不渲染
                if (mousemovePoint) {
                    let mouseMoveDist = this.getMouseMoveDistForBlock(block, x1, y1, mousemovePoint, mousedownPoint);
                    if (block.isPointIn && !block.transformPoint) {  // 如果鼠标悬浮在元素上,且不是控制点上 ,就是拖拽
                        let isInGroup = false;
                        GridSystem.groups.forEach(group => {
                            let gBlock = group.blocks.find(item => item === block);
                            if (gBlock) {
                                isInGroup = true;
                                group.blocks.forEach(gblock => {
                                    var { x: x2, y: y2, width: width2, height: height2 } = this.getPixelPosAndWH(gblock);
                                    let mouseMoveDist = this.getMouseMoveDistForBlock(gblock, x2, y2, mousemovePoint, mousedownPoint);
                                    gblock.draw(x2 + mouseMoveDist.x, y2 + mouseMoveDist.y, width2, height2); // 必须先画出来才能知道,鼠标是否在他身上
                                    gblock.isGrouped = true;
                                })
                            }
                        })
                        if (!isInGroup) {
                            block.draw(x1 + mouseMoveDist.x, y1 + mouseMoveDist.y, width1, height1);
                            this.setTouchBlock(block);
                        }
                    } else if (block.transformPoint) {  // 如果鼠标悬浮在控制点上,就开始形变
                        let { x: x2, y: y2, width: width3, height: height3, angle } = this.getPosbyControlPoint(block, x1, y1, width1, height1, mousemovePoint);
                        if (angle !== undefined) block.angle = angle;
                        block.draw(x2, y2, width3, height3, angle);
                        this.setTouchBlock(block);
                    } else if (!block.isGrouped) {
                        block.draw(x1, y1, width1, height1);
                        this.setTouchBlock(block);
                    }
                } else {
                    block.draw(x1, y1, width1, height1);
                }
            }
        });
    }

    // 碰撞检测
    setTouchBlock(c_block: Block) {
        let { x, y, width, height } = this.getPixelPosAndWH(c_block);
        this.blocks.forEach(block => {
            if (block != c_block && block.cbTouch) {
                let { x: x1, y: y1, width: width1, height: height1 } = this.getPixelPosAndWH(block);
                if (((x > x1 || x + width > x1) && (x < x1 + width1 || x + width < x1 + width1)) && ((y > y1 || y + height > y1) && (y < y1 + height1 || y + height < y1 + height1))) {
                    if (!c_block.isTouch) {
                        c_block.fisrtTouch && c_block.fisrtTouch(block);   // 触发事件
                    }
                    if (!block.isTouch) {
                        block.fisrtTouch && block.fisrtTouch(c_block);   // 触发事件
                    }
                    c_block.isTouch = true;
                    block.isTouch = true;
                    c_block.touching && c_block.touching(block);   // 触发事件
                    block.touching && block.touching(c_block);
                } else {
                    c_block.isTouch = false;
                }
            }
        })
    }

    /**
     * 判断元素是否在屏幕内
     * @param x 
     * @param y 
     * @param width 
     * @param height 
     * @param angle 
     * @returns 
     */
    isBoundrayPointInScreen(block: Block, x: number, y: number, width: number, height: number, angle: number = 0) {  // 像素值
        let hasRelative = false;
        for (let index = 0; index < GridSystem.groups.length; index++) {
            let group = GridSystem.groups[index];
            if (group.blocks.find(item => block == item)) { hasRelative = true; break; }
        }
        if (!hasRelative) {
            for (let index = 0; index < GridSystem.links.length; index++) {
                let link = GridSystem.links[index];
                if (link.blocks.find(item => block == item)) { hasRelative = true; break; }
            }
        }
        if (hasRelative) { return true }   // 判断有没有关联的事务, 有便不能不绘制
        let points = this.getBoundaryPoints(x, y, width, height, angle, false)
        let bool = points.some(point => {
            return point.x > 0 && point.x < this.canvasWidth && point.y > 0 && point.y < this.canvasHeight;
        })
        return bool;
    }

    /**
     * 绘制线性元素
     */
    drawLines(mousemovePoint?: IPoint, mousedownPoint?: IPoint) {
        this.lines.forEach((line: Line) => {
            let newPoints: IPoint[] = []
            line.points.forEach(point => {
                newPoints.push(this.getPixelPos(point))
            })
            if (line.transformPoint && mousemovePoint) {
                let index = line.controlPoints.findIndex(item => item == line.transformPoint);
                let mouseMoveDist = this.getMouseMoveDistForBlock(line.transformPoint, newPoints[index].x, newPoints[index].y, mousemovePoint, mousedownPoint);
                newPoints[index].x += mouseMoveDist.x;
                newPoints[index].y += mouseMoveDist.y;
            }
            if (this.hoverNode == line && mousemovePoint) {
                newPoints.forEach((point, index) => {
                    let mouseMoveDist = this.getMouseMoveDistForLine(line, index, point, mousemovePoint, mousedownPoint);
                    point.x += mouseMoveDist.x;
                    point.y += mouseMoveDist.y;
                })
            }
            line.draw(newPoints);
        })
    }

    // 获取元素每一帧要移动的距离
    getMouseMoveDistForLine(line: Line, index: number, point:IPoint, mousemovePoint: IPoint, mousedownPoint?: IPoint) {
        let mouseMoveDist = {  // 要移动的距离
            x: mousemovePoint.x - point.x,
            y: mousemovePoint.y - point.y,
        }
        if (mousedownPoint && line.lastDistArr) {
            if (!line.lastDistArr[index]) {
                line.lastDistArr[index] = { x: 0, y: 0 }
                line.lastDistArr[index].x = mousedownPoint.x - point.x
                line.lastDistArr[index].y = mousedownPoint.y - point.y
            }
            mouseMoveDist.x -= line.lastDistArr[index].x
            mouseMoveDist.y -= line.lastDistArr[index].y
        }
        return mouseMoveDist;
    }

    // 获取元素每一帧要移动的距离
    getMouseMoveDistForBlock(block: Block, x: number, y: number, mousemovePoint: IPoint, mousedownPoint?: IPoint) {
        let mouseMoveDist = {  // 要移动的距离
            x: mousemovePoint.x - x,
            y: mousemovePoint.y - y,
        }
        if (mousedownPoint) {
            if (!block.lastDist) {
                block.lastDist = { x: 0, y: 0 }
                block.lastDist.x = mousedownPoint.x - x
                block.lastDist.y = mousedownPoint.y - y
            }
            mouseMoveDist.x -= block.lastDist.x
            mouseMoveDist.y -= block.lastDist.y
        }
        return mouseMoveDist;
    }

    /**
     * 绘制连线元素,link元素是被动地实时的跟随元素变化而变化
     */
    drawLinks() {
        this.links.forEach((link) => {
            let cbDraw: boolean = true;
            for (let index = 0; index < link.blocks.length; index++) {
                const lBlock = link.blocks[index];
                cbDraw = !!this.blocks.find(block => lBlock == block);
                if (!cbDraw) {
                    break;
                }
            }
            if (!cbDraw) {
                return
            }
            let endBlock = link.blocks[link.blocks.length - 1]  // 终点元素
            let endArrow = link.arrows[link.arrows.length - 1]  // 终点箭头
            let startPoint = link.points[0]  // 起点
            let endPoint = link.points[link.points.length - 1]  // 终点
            if (link.arrows && link.arrows.length > 0) {  // 对终点做些改变,连接到元素的边缘
                let closerPoint = this.getCloserPoint(startPoint, endBlock);
                endPoint.x = closerPoint.x;
                endPoint.y = closerPoint.y;
            }
            link.draw(link.points);
            if (endArrow && endArrow.linkMark == LinkMark.END) {  // 画箭头
                endArrow.linePoints = link.actualPoints;
                // let {x:x1,y:y1} = this.getPixelPos(endArrow.linePoints[0]);
                // endArrow.linePoints[0].x = x1;
                // endArrow.linePoints[0].y = y1;

                // let {x:x1,y:y1} = this.getPixelPos(endArrow.linePoints[endArrow.linePoints.length - 1]);
                // endArrow.linePoints[0].x = x1;
                // endArrow.linePoints[0].y = y1;
                var { x: x1, y: y1, width: width1, height: height1 } = this.getPixelPosAndWH(endArrow);
                endArrow.draw(x1, y1, width1, height1)
            }
        })
    }

    // 获取点与边最近的点
    getCloserPoint(startPoint: IPoint, block: Block): IPoint {
        let closerPoint = { x: 0, y: 0 };
        let points = this.getBoundaryPoints(block.x, block.y, block.width, block.height, block.angle, !block.isFixedPos);  // leftTop, rightTop, rightBottom, leftBottom
        let lines = getMinDistLine(startPoint, [[points[0], points[1]], [points[1], points[2]], [points[2], points[3]], [points[3], points[0]]]);
        let res = point2SegDist(startPoint, lines[0], lines[1]);
        if (res.type) { // 如果垂足在线段内,就采用
            closerPoint = res.point;
        } else {  // 否则就去两个顶点找最近的
            let vector1 = getVector(lines[0], startPoint)
            let vector2 = getVector(lines[1], startPoint)
            let len1 = getVectorLength(vector1);
            let len2 = getVectorLength(vector2);
            if (len1 < len2) {
                closerPoint = lines[0]
            } else {
                closerPoint = lines[1]
            }
        }
        return closerPoint;
    }

    /**
     * 监听cnavas内的鼠标或键盘事件 
     */
    initEventListener() {
        this.myCanvas.addEventListener("mousedown", this.mouseDown.bind(this));
        this.myCanvas.addEventListener("mousewheel", this.mousewheel.bind(this));
        this.myCanvas.addEventListener("mousemove", this.mouseMove.bind(this));
        document.addEventListener(MyEvent.DB_CLICK, this.mouseDbclick.bind(this));
        // window.addEventListener("resize", ()=>{
        //     // this.drawLineGrid();
        // });
        new Shortcuts(["ctrl", "z"], this.undo.bind(this));
        new Shortcuts(["ctrl", "y"], this.restore.bind(this));
        new Shortcuts(["del"], this.remove.bind(this));
    }

    /**
     * 撤销与恢复功能
     */
    undo() {
        this.stack.undo(this.blocks)
    }
    restore() {
        this.stack.restore(this.blocks)
    }

    /**
     * 滚轮滚动事件,重绘网格
     * @param e 
     * @returns 
     */
    mousewheel(e: any) {
        e.preventDefault();
        if (this.scale >= CoordinateSystem.MAX_SCALESIZE) {
            this.scale -= CoordinateSystem.SCALE_ABILITY;
            return;
        }
        if (this.scale <= CoordinateSystem.MIN_SCALESIZE) {
            this.scale += CoordinateSystem.SCALE_ABILITY;
            return;
        }
        let { x, y } = getMousePos(this.myCanvas, e);
        let that = this;
        if (e.wheelDelta > 0) {
            this.scale += CoordinateSystem.SCALE_ABILITY;
            back2center();
        } else {
            this.scale -= CoordinateSystem.SCALE_ABILITY;
            back2center();
        }

        function back2center() {
            var girdSize = that.getPixelSize(CoordinateSystem.GRID_SIZE);
            var different = girdSize - that.lastGirdSize;
            that.pageSlicePos.x -= ((x - that.lastPageSlicePos.x) / that.lastGirdSize) * different;
            that.pageSlicePos.y -= ((y - that.lastPageSlicePos.y) / that.lastGirdSize) * different;
        }

        this.lastGirdSize = this.getPixelSize(CoordinateSystem.GRID_SIZE);
        this.lastPageSlicePos.x = this.pageSlicePos.x;
        this.lastPageSlicePos.y = this.pageSlicePos.y;

        let event = new CustomEvent("pointwheel");
        document.dispatchEvent(event);
        // this.drawLineGrid();
    };

    // 监听鼠标移动,看有没有悬浮在某个元素上
    mouseMove(e: any) {
        if (!this.dragNode) {
            this.mouseMovePoint = getMousePos(this.myCanvas, e);
            this.hoverNode = this.findMouseOnPoint(this.mouseMovePoint, e);
            if (this.hoverNode) {
                this.myCanvas.style.cursor = "pointer"
            } else {
                this.myCanvas.style.cursor = "auto"
            }
        }
    }

    mouseDbclick(ev: any) {
        let e = ev.detail;
        if (!this.dragNode) {
            let mouseMovePoint = getMousePos(this.myCanvas, e);
            this.hoverNode = this.findMouseOnPoint(mouseMovePoint, e);
            if (this.hoverNode) {
                if (this.hoverNode instanceof MyText) {
                    this.hoverNode.flicker();
                }
            } else {
            }
        }
    }

    /**
     * 鼠标点击判断有没有元素被选中, 选中拖动或形变 canvas 动态渲染，拖动时，动态设置 pageSlicePos 的值
     * @param e Event
     */
    mouseDown(e: any) {
        if (new Date().getTime() - this.lastMouseDownTime < 300) {  // 如果是双击
            let event = new CustomEvent(MyEvent.DB_CLICK, { detail: e });
            document.dispatchEvent(event);
            this.lastMouseDownTime = new Date().getTime();
            return;
        }
        this.lastMouseDownTime = new Date().getTime();
        let event = new CustomEvent(MyEvent.POINT_DOWN, { detail: e });
        document.dispatchEvent(event);
        let clickPoint: IPoint = {
            x: e.clientX,
            y: e.clientY
        }
        let mouseDownPoint = getMousePos(this.myCanvas, e);
        if (!GridSystem.isSelectArea) {
            const { x, y } = this.pageSlicePos;
            let blockMouseOn = this.findMouseOnPoint(mouseDownPoint, e);
            // console.log(blockMouseOn, "blockMouseOn.....");

            this.dragNode = blockMouseOn;
            this.myCanvas.style.cursor = "move"
            var fn1 = this.dragBlock.bind(this, clickPoint, blockMouseOn);
            var fn2 = this.dragCanvas.bind(this, clickPoint, { x, y });
            var fn3 = clearEventAndData.bind(this, () => {
                this.stack.push(this.blocks);  // 记录历史操作
            })
            var fn4 = clearEventAndData.bind(this, () => { })
            if (blockMouseOn) {
                if (!blockMouseOn.parentBlock) {
                    this.focusNode = blockMouseOn;  // 被点击的元素是焦点元素
                    blockMouseOn.mouseDown && blockMouseOn.mouseDown(e)  // 如果有点击事件，则触发
                    // this.drawLineGrid()
                } else {
                    this.focusNode = blockMouseOn.parentBlock;  // 被点击的元素是焦点元素
                    // this.drawLineGrid()
                }
                if (blockMouseOn instanceof MyControlPoint && blockMouseOn.parentBlock) {  // 如果是控制点
                    blockMouseOn.parentBlock.transformPoint = blockMouseOn;
                }
                document.addEventListener("mousemove", fn1)
                document.body.style.userSelect = "none"
                document.addEventListener("mouseup", fn3)
            } else {
                this.focusNode = null;
                // 没点到元素才可以拖动画布
                document.addEventListener("mousemove", fn2)
                document.body.style.userSelect = "none"
                document.addEventListener("mouseup", fn4);
                this.blocks.forEach(block => {   // 清除文本闪烁
                    if (block instanceof MyText) {
                        block.stopFlicker();
                    }
                })
                // this.drawLineGrid();
            }

            // 清除事件以及重置变量
            let that = this;
            function clearEventAndData(fn: Function, e: any) {
                fn(getMousePos(that.myCanvas, e));
                that.dragNode = null;
                document.removeEventListener("mousemove", fn1)
                document.removeEventListener("mousemove", fn2)
                document.removeEventListener("mouseup", fn3)
                document.removeEventListener("mouseup", fn4)
                that.blocks.forEach(block => {  // 修正值重置为null
                    block.lastDist = null;
                    block.isPointIn = false;
                    block.isDraged = false;
                    block.transformPoint = null;
                })
                that.lines.forEach(block => {  // 修正值重置为null
                    block.lastDist = null;
                    block.isDraged = false;
                    block.transformPoint = null;
                })
                that.myCanvas.style.cursor = "auto"
                document.body.style.userSelect = "auto"
                that.drawLineGrid()
            }
        } else {
            this.rectArea && this.remove(this.rectArea);
            this.rectArea = this.createRect({ x: mouseDownPoint.x, y: mouseDownPoint.y, width: 0, height: 0, cbTransform: false });
            this.rectArea.cbSelect = false;
            this.rectArea.fill = CoordinateSystem.AREA_FILL_COLOR;
            var fn1 = this.drawRectArea.bind(this, this.rectArea);
            var fn2 = clearEventAndData.bind(this, this.rectArea, () => {
                this.rectArea = null
            })
            this.myCanvas.addEventListener("mousemove", fn1)
            this.myCanvas.addEventListener("mouseup", fn2)
            let that = this;
            function clearEventAndData(rectArea: Block, fn: Function, e: any) {
                that.myCanvas.removeEventListener("mousemove", fn1)
                that.myCanvas.removeEventListener("mouseup", fn2)
                fn && fn();
                that.remove(rectArea);
            }
        }
    };

    /**
     * 绘制自定义区域
     * @param rect 
     * @param e 
     */
    drawRectArea(rect: Block, e: any) {
        var { x, y } = this.getPixelPosAndWH(rect);
        var { x: x1, y: y1 } = getMousePos(this.myCanvas, e);
        rect.width = this.getRelativeSize(x1 - x);
        rect.height = this.getRelativeSize(y1 - y);
        // this.drawLineGrid();
        let event = new CustomEvent(MyEvent.DRAW_AREA, {
            detail: this.findBlocksInArea(rect)
        });
        document.dispatchEvent(event);
    }

    /**
     * 获取那些元素被自定义区域包含
     * @param rect 
     * @returns 
     */
    findBlocksInArea(rect: Block) {
        let inAreaBlocks: Block[] = [];
        this.blocks.forEach(block => {
            if (block && block !== rect) {
                let boundaryPoints = this.getBoundaryPoints(block.x, block.y, block.width, block.height, block.angle);
                let allIn = boundaryPoints.every(point => isPointInRect(this.getPixelPosAndWH(rect), point))
                if (allIn) inAreaBlocks.push(block)
            }
        })
        return inAreaBlocks;
    }

    /**
     * 获取矩形四个顶点, 如果元素有旋转,需要额外计算旋转后的坐标
     * @param x1 
     * @param y1 
     * @param width1 
     * @param height1 
     * @param angle 
     * @param transPos  // 是否需要转化为像素值
     * @returns 
     */
    getBoundaryPoints(x1: number, y1: number, width1: number, height1: number, angle: number = 0, transPos = true) {
        let x = x1, y = y1, width = width1, height = height1;
        if (transPos) {
            let { x: x2, y: y2, width: width2, height: height2 } = this.getPixelPosAndWH({ x: x1, y: y1, width: width1, height: height1 })
            x = x2;
            y = y2;
            width = width2;
            height = height2;
        }
        let leftTop: IPoint = { x: x, y: y };
        let leftBottom: IPoint = { x: x, y: y + height };
        let rightTop: IPoint = { x: x + width, y: y };
        let rightBottom: IPoint = { x: x + width, y: y + height };

        if (angle != 0) {
            let originPoint = { x: x + width / 2, y: y + height / 2 }
            leftTop = getRotatePoint(leftTop, originPoint, angle);
            rightTop = getRotatePoint(rightTop, originPoint, angle);
            rightBottom = getRotatePoint(rightBottom, originPoint, angle);
            leftBottom = getRotatePoint(leftBottom, originPoint, angle);
        }
        return [leftTop, rightTop, rightBottom, leftBottom]
    }

    // 拖拽元素
    dragBlock(clickPoint: IPoint, block: Block | undefined, ev: any) {
        if (!block) return
        block.isDraged = true;
        let movePoint = {
            x: ev.clientX,
            y: ev.clientY
        }
        this.drawLineGrid(getMousePos(this.myCanvas, movePoint), getMousePos(this.myCanvas, clickPoint));
        if (block.mouseOn && ev) block.mouseOn(ev);
    }

    // 拖拽画布
    dragCanvas(clickPoint: IPoint, pageSlicePos: IPoint, ev: any) {
        let movePoint = {
            x: ev.clientX,
            y: ev.clientY
        }
        this.pageSlicePos.x = pageSlicePos.x + (movePoint.x - clickPoint.x);
        this.pageSlicePos.y = pageSlicePos.y + (movePoint.y - clickPoint.y);
        // this.drawLineGrid();
    }

    findMouseOnPoint(mousePoint: IPoint, e?: any): Block | Line | null | undefined {
        let blockMouseOn: Block | Line | null | undefined;
        blockMouseOn = this.findMouseOnRectOrControlPoint(this.blocks, mousePoint, e);
        if (!blockMouseOn) {
            blockMouseOn = this.findMouseOnLineOrControlPoint(this.lines, mousePoint, e);
        }
        return blockMouseOn;
    }

    /**
     * 判断鼠标点是否在block元素内,或在控制点内
     * @param blocks 
     * @param mousePoint 
     * @returns 
     */
    findMouseOnRectOrControlPoint(blocks: Block[], mousePoint: IPoint, e?: any): Block | undefined {
        let pointInBlock;
        for (let index = 0; index < blocks.length; index++) {
            let block = blocks[index];
            if (!block.cbSelect || !block.cbMove) continue;
            if (block.parentBlock && !(block.parentBlock instanceof Block)) continue;
            let preIsPointIn = block.isPointIn;   // 记录当前鼠标与元素的状态
            var width2 = this.getPixelSize(block.width, block);
            var height2 = this.getPixelSize(block.height, block);
            let { x: x1, y: y1 } = { x: 0, y: 0 };
            if (block instanceof MyControlPoint && block.parentBlock) {   // 如果是控制点
                let parentBlock = block.parentBlock;
                let { x: x3, y: y3 } = this.getPixelPos(block);
                if (parentBlock.angle != 0) {
                    let { x: x2, y: y2 } = this.getPixelPos(parentBlock)
                    let parentWidth = this.getPixelSize(parentBlock.width);
                    let parentHeight = this.getPixelSize(parentBlock.height);
                    let centerPoint = block.getCenterPoint(x3, y3, block.width, block.height)
                    let { x: x4, y: y4 } = getRotatePoint({ x: x3, y: y3 }, parentBlock.getCenterPoint(x2, y2, parentWidth, parentHeight), parentBlock.angle);   // 旋转后的起始点， 左上角
                    let rotateCenterPoint = getRotatePoint(centerPoint, parentBlock.getCenterPoint(x2, y2, parentWidth, parentHeight), parentBlock.angle);  // 旋转后的中心点
                    let { x: x5, y: y5 } = getRotatePoint({ x: x4, y: y4 }, rotateCenterPoint, -parentBlock.angle);  // 恢复旋转的起始点
                    x1 = x5;
                    y1 = y5;
                } else {
                    x1 = x3;
                    y1 = y3;
                }
            } else {  // 如果是元素
                let { x: x2, y: y2 } = this.getPixelPos(block, block)
                x1 = x2;
                y1 = y2;
            }
            block.isPointIn = isPosInRotationRect(
                { x: x1, y: y1, width: width2, height: height2 },
                mousePoint,
                block.parentBlock ? block.parentBlock.getCenterPoint(x1, y1, width2, height2) : block.getCenterPoint(x1, y1, width2, height2),
                block.parentBlock ? block.parentBlock.angle : block.angle,
            );
            if (block.isPointIn) {
                let block2 = this.findMouseOnRectOrControlPoint(block.controlPoints, mousePoint, e);
                if (block.controlPoints.length > 0 && block2) {  // 优先设置为控制点
                    pointInBlock = block2;
                    break;
                } else {  // 没在控制点上,才是拖拽
                    pointInBlock = block;
                    if (block.mouseOn && e) block.mouseOn(e);
                    break;
                }
            } else if (block.controlPoints.length > 0) {
                pointInBlock = this.findMouseOnRectOrControlPoint(block.controlPoints, mousePoint, e);
                if (pointInBlock) {
                    break;
                }
            }
            if (block.mouseLeave && e && preIsPointIn && !block.isPointIn) {  // 离开只触发一次
                block.mouseLeave();
            }
        }
        return pointInBlock
    }

    /**
 * 判断鼠标点是否在Line元素内,或在控制点内
 * @param blocks 
 * @param mousePoint 
 * @returns 
 */
    findMouseOnLineOrControlPoint(lines: Line[], mousePoint: IPoint, e?: any): Block | Line | undefined {
        let pointInBlock;
        for (let index = 0; index < lines.length; index++) {
            const line = this.lines[index];
            let blocks = line.controlPoints;
            for (let index = 0; index < blocks.length; index++) {
                let block = blocks[index];
                let parentBlock = block.parentBlock;
                if (!block.cbSelect || !block.cbMove) continue;
                if (parentBlock && !(parentBlock instanceof Line)) continue;
                if (parentBlock && block instanceof MyControlPoint) {   // 如果是控制点
                    let { width, height } = block;
                    let { x: x1, y: y1 } = this.getPixelPos(block);
                    block.isPointIn = isPointInRect(
                        { x: x1, y: y1, width, height },
                        mousePoint,
                    );
                    if (block.isPointIn) {
                        pointInBlock = block;
                        break;
                    }
                }
            }
            if (!pointInBlock && line.isPointIn) {
                pointInBlock = line;
                break;
            }
        }
        return pointInBlock;
    }

    /**
     * 将某个元素移动另一个位置
     * @param block 移动的元素
     * @param speed 移动的速度
     * @param followCamera 镜头是否跟随移动
     */
    moveBlock(block: Block, speed: IPoint, followCamera: boolean = false,) {
        block.x += speed.x;
        block.y += speed.y;
        if (followCamera) {
            let { x: x1, y: y1 } = this.getPixelPos({ x: .1, y: 0 });
            this.pageSlicePos.x -= x1
            this.pageSlicePos.y -= y1
        }
        // this.drawLineGrid();
        requestAnimationFrame(() => { this.moveBlock(block, speed, followCamera) })
    }

    findBlockByName(name: string): Block | void {
        return this.blocks.find(block => block.name == name)
    }

    /**
     * 移动控制点改变元素大小, 参数都是未旋转的绝对像素
     * @param controlPointName 
     * @param x 
     * @param y 
     * @param width 
     * @param height 
     * @returns 
     */
    getPosbyControlPoint(block: Block, x: number, y: number, width: number, height: number, mouseMovePoint: IPoint): IStatus {  //根据控制点变化的坐标,计算出自己的坐标,宽高, 实际像素
        let { x: x1, y: y1 } = getRotatePoint({ x, y }, block.getCenterPoint(x, y, width, height), block.angle);   // 旋转后的起始点， 左上角

        let angle = block.angle;
        let mouseMoveDist = {
            x: mouseMovePoint.x - x1,
            y: mouseMovePoint.y - y1,
        }
        switch (block.transformPoint?.name) {
            case ControlPoint.LEFT_TOP_POINT:
                if (mouseMovePoint.x > x + width || mouseMovePoint.y > y + height) return { x, y, width, height, angle }  // 不能超出最小值
                x = mouseMovePoint.x
                y = mouseMovePoint.y
                width -= mouseMoveDist.x
                if (!(block instanceof MyText)) {
                    height -= mouseMoveDist.y
                } else {
                    height = width / block.text.length;
                }
                break;
            case ControlPoint.RIGHT_TOP_POINT:
                if (mouseMovePoint.x < x || mouseMovePoint.y > y + height) return { x, y, width, height, angle }
                y = mouseMovePoint.y
                width = mouseMoveDist.x
                if (!(block instanceof MyText)) {
                    height -= mouseMoveDist.y
                } else {
                    height = width / block.text.length;
                }
                break;
            case ControlPoint.LEFT_BOTTOM_POINT:
                if (mouseMovePoint.x > x + width || mouseMovePoint.y < y) return { x, y, width, height, angle }
                x = mouseMovePoint.x
                width -= mouseMoveDist.x
                if (!(block instanceof MyText)) {
                    height = mouseMoveDist.y
                } else {
                    height = width / block.text.length;
                }
                break;
            case ControlPoint.RIGHT_BOTTOM_POINT:
                if (mouseMovePoint.x < x || mouseMovePoint.y < y) return { x, y, width, height, angle }
                block.rotatePoint = { x, y }
                width = mouseMoveDist.x
                if (!(block instanceof MyText)) {
                    height = mouseMoveDist.y
                } else {
                    height = width / block.text.length;
                }
                break;
            case ControlPoint.ROTATE_POINT:
                let centerPoint = block.getCenterPoint(x, y, width, height);
                let dx = mouseMovePoint.x - centerPoint.x;
                let dy = mouseMovePoint.y - centerPoint.y;
                angle = Math.atan2(dy, dx) * (180 / Math.PI) + 90;
                break;
            default:
                break;
        }
        return {
            x,
            y,
            width,
            height,
            angle,
        }
    }

    /**
     * 通过鼠标点击去创建 元素
     * @param type 
     * @param width 
     * @param height 
     * @param text 
     */
    clickDrawBlock(type: string, width: number, height: number, text?: string) {
        let that = this;
        let option: IStatus = { x: 0, y: 0, width: 0, height: 0 };
        document.addEventListener(MyEvent.POINT_DOWN, getClickPoint)
        function getClickPoint(e: any) {
            let mouseDownPoint = getMousePos(that.myCanvas, e.detail);
            option.x = mouseDownPoint.x;
            option.y = mouseDownPoint.y;
            option.width = width;
            option.height = height;
            switch (type) {
                case BlockType.RECT:
                    that.createRect(option, getClickPoint);
                    break;
                case BlockType.TRIANGLE:
                    that.createTriangle(option, getClickPoint);
                    break;
                case BlockType.TEXT:
                    that.createText(option, text || '', getClickPoint)
                    break;
                case BlockType.IMAGE:
                    that.createImage(option, text || '', getClickPoint)
                case BlockType.LINE:
                    that.createLine(option, getClickPoint);
                    break;
                case BlockType.CIRCLE:
                    that.createCircle(option, getClickPoint);
                    break;
                case BlockType.POLYGON:
                    that.createPolygon(option, getClickPoint);
                    break;
                case BlockType.ARROW:
                    that.createArrow(option, getClickPoint);
                    break;
                default: break;
            }
        }
    }

    setBlockConfigs(block: Node, option: IStatus) { // 整体设置
        for (const key in option) {
            switch (key) {
                case "isFixedPos":
                    if (option.isFixedPos !== undefined) block.isFixedPos = option.isFixedPos;
                    break;
                case "isFixedSize":
                    if (option.isFixedSize !== undefined) block.isFixedSize = option.isFixedSize;
                    break;
                case "cbTransform":
                    if (option.cbTransform !== undefined) block.cbTransform = option.cbTransform;
                    break;
                case "cbSelect":
                    if (option.cbSelect !== undefined) block.cbSelect = option.cbSelect;
                    break;
                case "cbMove":
                    if (option.cbMove !== undefined) block.cbMove = option.cbMove;
                    break;
                default:
                    break;
            }
        }
    }

    // 创建矩形
    createRect(option: IStatus, getClickPoint?: Function) {
        getClickPoint && document.removeEventListener(MyEvent.POINT_DOWN, getClickPoint);
        let { x, y, width, height } = this.getRelativePosAndWH(option.x, option.y, option.width, option.height, option)
        var rect = new MyRect(x, y, width, height);
        this.setBlockConfigs(rect, option);
        rect.draw(option.x, option.y, option.width, option.height);
        this.add(rect);
        getClickPoint && document.removeEventListener(MyEvent.POINT_DOWN, getClickPoint);
        return rect;
    }

    // 创建箭头
    createArrow(option: IStatus, getClickPoint?: Function) {
        getClickPoint && document.removeEventListener(MyEvent.POINT_DOWN, getClickPoint);
        let { x, y, width, height } = this.getRelativePosAndWH(option.x, option.y, option.width, option.height, option)
        var arrow = new MyArrow(x, y, width, height);
        this.setBlockConfigs(arrow, option);
        arrow.draw(option.x, option.y, option.width, option.height);
        this.add(arrow);
        getClickPoint && document.removeEventListener(MyEvent.POINT_DOWN, getClickPoint);
        return arrow;
    }


    // 创建三角形
    createTriangle(option: IStatus, getClickPoint?: Function) {
        getClickPoint && document.removeEventListener(MyEvent.POINT_DOWN, getClickPoint);
        let { x, y, width, height } = this.getRelativePosAndWH(option.x, option.y, option.width, option.height, option)
        var triangle = new MyTriangle(x, y, width, height);
        this.setBlockConfigs(triangle, option);
        triangle.draw(option.x, option.y, option.width, option.height);
        this.add(triangle);
        getClickPoint && document.removeEventListener(MyEvent.POINT_DOWN, getClickPoint);
        return triangle;
    }

    // 创建文本
    createText(option: IStatus, text: string, getClickPoint?: Function) {
        getClickPoint && document.removeEventListener(MyEvent.POINT_DOWN, getClickPoint);
        let textWidth = this.ctx.measureText(text).width;
        let { x, y, width, height } = this.getRelativePosAndWH(option.x, option.y, textWidth, option.height, option)
        var txt = new MyText(text, x, y, width, height)
        this.setBlockConfigs(txt, option);
        txt.draw(option.x, option.y, option.width, option.height);
        this.add(txt);
        getClickPoint && document.removeEventListener(MyEvent.POINT_DOWN, getClickPoint);
        return txt;
    }

    // 创建图片
    createImage(option: IStatus, src: string, getClickPoint?: Function) {
        getClickPoint && document.removeEventListener(MyEvent.POINT_DOWN, getClickPoint);
        let { x, y, width, height } = this.getRelativePosAndWH(option.x, option.y, option.width, option.height, option)
        var image = new MyMark(src, x, y, width, height);
        this.setBlockConfigs(image, option);
        image.draw(option.x, option.y, option.width, option.height);
        this.add(image);
        getClickPoint && document.removeEventListener(MyEvent.POINT_DOWN, getClickPoint);
        return image;
    }

    tempLine: MyLine | null = null;
    // 创建线段
    createLine(option: IStatus, getClickPoint?: Function) {
        // getClickPoint && document.removeEventListener(MyEvent.POINT_DOWN, getClickPoint);
        let { x, y } = this.getRelativePos({ x: option.x, y: option.y })
        if (!this.tempLine) {
            this.tempLine = new MyLine([{ x, y }]);
            this.add(this.tempLine);

            let overline = () => {
                this.tempLine = null;
                getClickPoint && document.removeEventListener(MyEvent.POINT_DOWN, getClickPoint);
                document.removeEventListener(MyEvent.DB_CLICK, overline);
            }
            document.addEventListener(MyEvent.DB_CLICK, overline);
        } else {
            this.tempLine.addPoint({ x, y });
            // this.drawLineGrid();
        }
    }

    tempPolygon: MyLine | null = null;  // 临时变量
    // 创建线段
    createPolygon(option: IStatus, getClickPoint?: Function) {
        // getClickPoint && document.removeEventListener(MyEvent.POINT_DOWN, getClickPoint);
        let { x, y } = this.getRelativePos({ x: option.x, y: option.y })
        if (!this.tempPolygon) {
            this.tempPolygon = new MyPolygon([{ x, y }]);
            this.add(this.tempPolygon);
            let overline = () => {
                // this.tempPolygon && this.tempPolygon.addPoint({ x, y });
                this.tempPolygon = null;
                getClickPoint && document.removeEventListener(MyEvent.POINT_DOWN, getClickPoint);
                document.removeEventListener(MyEvent.DB_CLICK, overline);
            }
            document.addEventListener(MyEvent.DB_CLICK, overline);
        } else {
            this.tempPolygon.addPoint({ x, y });
            // this.drawLineGrid();
        }
    }

    // 创建圆
    createCircle(option: IStatus, getClickPoint?: Function) {
        getClickPoint && document.removeEventListener(MyEvent.POINT_DOWN, getClickPoint);
        let { x, y, width, height } = this.getRelativePosAndWH(option.x, option.y, option.width, option.height, option)
        var circle = new MyCircle(x, y, width, height);
        this.setBlockConfigs(circle, option);
        circle.draw(option.x, option.y, option.width, option.height);
        this.add(circle);
        getClickPoint && document.removeEventListener(MyEvent.POINT_DOWN, getClickPoint);
        return circle;
    }


    /**
     * 根据id 删除元素
     * @param id 
     */
    remove(id?: string | Block): boolean {
        if (id instanceof Block) {
            let block = this.blocks.find(item => item === id);
            if (block) {
                id = block.id;
            }
        }
        if (!id && this.focusNode) {
            id = this.focusNode?.id
        } else if (!id && !this.focusNode) {
            return false
        }
        let targetNodeIndex = this.blocks.findIndex(block => block.id === id);
        if (!targetNodeIndex && targetNodeIndex != 0) {
            throw "id不存在"
        }
        this.blocks.splice(targetNodeIndex, 1)
        // this.drawLineGrid();
        this.stack.push(this.blocks);  // 记录历史操作
        return true;
    }

    pop() {
        this.blocks.pop();
        // this.drawLineGrid();
        this.stack.push(this.blocks);  // 记录历史操作
    }

    /**
     * 添加一个元素到画布当中
     * @param block 
     */
    add(block: Node | null): boolean {
        if (!block) return false;
        if (block instanceof Block) {
            if (this.blocks.find(item => item === block)) return false;
            this.focusNode = block;
            this.blocks.push(block);
            this.stack.push(this.blocks);  // 记录历史操作
        } else if (block instanceof Link) {
            if (this.links.find(item => item === block)) return false;
            this.links.push(block);
            // this.stack.push(this.blocks);  // 记录历史操作
        } else if (block instanceof MyPolygon || block instanceof MyLine) {
            if (this.lines.find(item => item === block)) return false;
            this.lines.push(block);
        }
        this.blocks = this.blocks.sort((a, b) => a.zIndex - b.zIndex);  // 按层级排序,排在最后的显示在最上层
        // this.drawLineGrid();
        return true;
    }
    /**
     * 判断class是否可被绘制
     * @param block 
     * @returns 
     */
    cbDrawClass(block: Block) {
        return block instanceof MyRect ||
            block instanceof MyText ||
            block instanceof MyMark ||
            block instanceof MyTriangle ||
            block instanceof MyCustom ||
            block instanceof MyCircle || !block.isBindLink
    }

    /**
     * 绘制控制点
     * @param block 
     * @param rectX 
     * @param rectY 
     * @param rectWidth 
     * @param rectHeight 
     */
    setRectControls(block: Block, rectX: number, rectY: number, rectWidth: number, rectHeight: number) {  // 实际像素

        let rotatePoint1 = getRotatePoint({ x: rectX, y: rectY }, block.getCenterPoint(rectX, rectY, rectWidth, rectHeight), block.angle)
        if (!block.controlPoints || block.controlPoints.length == 0) {
            var leftTopPoint = new MyControlPoint(block.x, block.y);
            leftTopPoint.name = ControlPoint.LEFT_TOP_POINT;

            var rightTopPoint = new MyControlPoint(block.x, block.y);
            rightTopPoint.name = ControlPoint.RIGHT_TOP_POINT;

            var leftBottomPoint = new MyControlPoint(block.x, block.y);
            leftBottomPoint.name = ControlPoint.LEFT_BOTTOM_POINT;

            var rightBottomPoint = new MyControlPoint(block.x, block.y);
            rightBottomPoint.name = ControlPoint.RIGHT_BOTTOM_POINT;

            var rotatePoint = new MyControlPoint(block.x, block.y);
            rotatePoint.name = ControlPoint.ROTATE_POINT;

            block.controlPoints = [leftTopPoint, rightTopPoint, leftBottomPoint, rightBottomPoint, rotatePoint];
            // block.controlPoints = [rightBottomPoint];
            block.controlPoints.forEach(controlPoint => {
                controlPoint?.setParentBlock(block)
            })
        }
        block.drawControls(rectX, rectY, rectWidth, rectHeight);

    }

    setLineControls(block: Line, points: IPoint[]) {  // 实际像素
        if (!block.controlPoints || block.controlPoints.length == 0) {
            let controlPoints: MyControlPoint[] = [];
            points.forEach(point => {
                var controlPoint = new MyControlPoint(point.x, point.y);
                controlPoints.push(controlPoint)
            })
            block.controlPoints = controlPoints;
            block.controlPoints.forEach(controlPoint => controlPoint?.setParentBlock(block))
        }
        block.drawControls(points);
    }

    // 将元素移动到画中间
    toCenter(block: Block) {
        let { x, y, width, height } = this.getPixelPosAndWH(block)
        let position = block.getCenterPoint(x, y, width, height);
        let canvasCenter = { x: this.myCanvas.width / 2, y: this.myCanvas.height / 2 }
        let distX = canvasCenter.x - position.x;
        let distY = canvasCenter.y - position.y;
        runAnimate(this.pageSlicePos, { x: this.pageSlicePos.x + distX, y: this.pageSlicePos.y + distY }, 200, (e: any) => {
            this.pageSlicePos.x = e.x;
            this.pageSlicePos.y = e.y;
            // this.drawLineGrid();
        })

    }

    /**
     * 移动画布到指定位置
     * @param position 
     * @param duration 
     */
    toSomeWhere(position: IPoint, duration: number = 2000) {
        runAnimate(this.pageSlicePos, position, duration, (e: any) => {
            this.pageSlicePos.x = e.x;
            this.pageSlicePos.y = e.y;
            // this.drawLineGrid();
        })
    }

    /**
     * 静态方法
     * @param group 
     */
    static addGroup(group: Group) {
        GridSystem.groups.push(group)
    }

    /**
     * 静态方法
     * @param group 
     */
    static addLink(link: Link) {
        GridSystem.links.push(link)
    }

    // 根据class的名字创建元素
    static createFetureByClass(nodeStatus: IStatus): Block | null {
        let block: Block | null = null;
        switch (nodeStatus.class) {
            case BlockType.RECT:
                block = new MyRect(nodeStatus.x, nodeStatus.y, nodeStatus.width, nodeStatus.height)
                break;
            case BlockType.TRIANGLE:
                block = new MyTriangle(nodeStatus.x, nodeStatus.y, nodeStatus.width, nodeStatus.height)
                break;
            case BlockType.TEXT:
                block = new MyText(nodeStatus.text, nodeStatus.x, nodeStatus.y, nodeStatus.width, nodeStatus.height)
                break;
            case BlockType.IMAGE:
                if (nodeStatus.src) block = new MyMark(nodeStatus.src, nodeStatus.x, nodeStatus.y, nodeStatus.width, nodeStatus.height)
                // case BlockType.LINE:
                //     block = new MyLine([])
                break;
            case BlockType.CIRCLE:
                block = new MyCircle(nodeStatus.x, nodeStatus.y, nodeStatus.width, nodeStatus.height)
                break;
            // case BlockType.POLYGON:
            //     block = new MyPolygon([])
            //     break;
            default: break;
        }
        // if(block) {block.id = nodeStatus.id};
        return block;
    }

    // 修改配置
    setConfigs(options: IConfig) {
        for (const key in options) {
            this.blocks.forEach(block => {
                block[key] = GridSystem[key] = options[key]
            })
            this.lines.forEach(line => {
                line[key] = options[key]
            })
        }
    }

    /**
     * 根据相对坐标获取绝对坐标
     * @param point 
     * @returns 
     */
    getPixelPos(point: IPoint, block?: Block | IStatus): IPoint {
        if (block && block.isFixedPos) {
            return {
                x: point.x,
                y: point.y
            }
        } else {
            return {
                x: this.pageSlicePos.x + (point.x / CoordinateSystem.GRID_SIZE) * this.scale,
                y: this.pageSlicePos.y + (point.y / CoordinateSystem.GRID_SIZE) * this.scale,
            };
        }
    }

    /**
     * 根据绝对坐标获取相对坐标
     * @param pageSlicePos 
     * @param basicGirdSize 
     * @param scale 
     * @param point 
     * @returns 
     */
    getRelativePos(point: IPoint, block?: Block | IStatus): IPoint {
        if (block && block.isFixedPos) {
            return {
                x: point.x,
                y: point.y
            }
        } else {
            return {
                x: ((point.x - this.pageSlicePos.x) / this.scale) * CoordinateSystem.GRID_SIZE,
                y: ((point.y - this.pageSlicePos.y) / this.scale) * CoordinateSystem.GRID_SIZE,
            };
        }
    }
    getRelativePosX(x: number, block?: Block | IStatus): number {
        if (block && block.isFixedPos) {
            return x
        } else {
            return ((x - this.pageSlicePos.x) / this.scale) * CoordinateSystem.GRID_SIZE
        }
    }
    getRelativePosY(y: number, block?: Block | IStatus): number {
        if (block && block.isFixedPos) {
            return y
        } else {
            return ((y - this.pageSlicePos.y) / this.scale) * CoordinateSystem.GRID_SIZE
        }
    }

    /**
     * 根据相对大小获取绝对大小
     * @param basicGirdSize 
     * @param scale 
     * @returns 
     */
    getPixelSize(size: number, block?: Block | IStatus) {
        if (block && block.isFixedSize) {
            return size;
        } else {
            return size * this.scale;
        }
    }

    /**
     * 根据绝对大小获取相对大小
     * @param size 
     * @param block 
     * @returns 
     */
    getRelativeSize(size: number, block?: Block | IStatus) {
        if (block && block.isFixedSize) {
            return size;
        } else {
            return size / this.scale;
        }
    }
    /**
     * 根据block的相对坐标获取绝对坐标
     * @param block 
     * @returns 
     */
    getPixelPosAndWH(block: Block | IStatus) {  // 元素的像素坐标
        if (block.isFixedSize) {
            return { x: block.x, y: block.y, width: block.width, height: block.height }
        }
        let { x, y } = this.getPixelPos(block, block);
        var width = this.getPixelSize(block.width, block);
        var height = this.getPixelSize(block.height, block);
        return {
            x,
            y,
            width,
            height,
        }
    }

    /**
     * 根据block的绝对坐标获取相对坐标
     * @param x1 
     * @param y1 
     * @param width1 
     * @param height1 
     * @returns 
     */
    getRelativePosAndWH(x1: number, y1: number, width1: number, height1: number, block?: Block | IStatus) {  // 元素的绝对坐标
        if (block && block.isFixedSize) {
            return { x: x1, y: y1, width: width1, height: height1 }
        }
        let { x, y } = this.getRelativePos(
            { x: x1, y: y1 }, block
        );
        let width = this.getRelativeSize(width1, block)
        let height = this.getRelativeSize(height1, block)
        return {
            x,
            y,
            width,
            height,
        }
    }

    // 判断某个网格内有没有元素
    hasBlockByGridCoord(pool: Block[], x: number, y: number): Block | undefined {
        let target: Block | undefined;
        for (let index = 0; index < pool.length; index++) {
            const block = pool[index];
            if (block.gridCoord.x == x && block.gridCoord.y == y) {
                target = block;
                break;
            }
        }
        return target;
    }

    // 根据点击坐标获取网格坐标
    getGridCoordByClick(e: any) {
        let { x, y } = getMousePos(this.myCanvas, e);
        let gridSize = CoordinateSystem.GRID_SIZE * GridSystem.gls.scale;  // 实际网格单元大小
        let x2 = x > this.pageSlicePos.x ? Math.ceil((x - this.pageSlicePos.x) / gridSize) : Math.floor((x - this.pageSlicePos.x) / gridSize);
        let y2 = y > this.pageSlicePos.y ? Math.ceil((y - this.pageSlicePos.y) / gridSize) : Math.floor((y - this.pageSlicePos.y) / gridSize);
        return { x: x2, y: y2 }
    }

    // 根据网格坐标获取相对坐标
    getPosByGridCoord(x: number, y: number): IPoint {
        let gridSize = CoordinateSystem.GRID_SIZE * CoordinateSystem.GRID_SIZE;  // 实际网格单元大小
        return {
            x: x > 0 ? gridSize * (x - 1) : gridSize * x,
            y: y > 0 ? gridSize * (y - 1) : gridSize * y,
        }
    }

    loadFont(fontFamily:FontFamily) {
        const fontface = new FontFace(fontFamily, `url(${fontMap.get(FontFamily.ZONGYI)})`);
        if (!document.fonts.has(fontface)) {
            fontface.load().then(function (loadFace) {
                console.log("字体加载完毕!");
                document.fonts.add(loadFace);
            });
        }
    }
}

export default GridSystem